package com.example.administrator.demorecyclerview.refresh;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.NestedScrollingChild2;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.NestedScrollingParent2;
import android.support.v4.view.NestedScrollingParentHelper;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.OverScroller;


/**
 * Created by Administrator on 2017/11/20.
 */

/**
 * 1、onTouchEvent中prev滑动
 */
public class MySwipeRefreshLayout extends ViewGroup implements NestedScrollingParent2, NestedScrollingChild2 {

    //    private boolean mLoading;
//    private boolean mRefreshing;
//    private final int[] mParentOffsetInWindow = new int[2];


    private static final float SCROLL_CONSUMED_RATIO = 0.75f;
    private static final int OVERSTEP_HEIGHT = 200;
    private static final int FLAG_FREE = 0;
    private static final int FLAG_REFRESHING = 0x01;
    private static final int FLAG_LOADINGING = 0x02;
    private static final int FLAG_FINISHED = 0x04;
    private static final int MASK_BUSY = FLAG_REFRESHING | FLAG_LOADINGING;

    private static final int FLAG_BACK_SCROLLING = 0x08;
    private static final int FLAG_AUTO_REFRESH_SCROLLING = 0x10;
    private static final int MASK_SCROLLING = FLAG_BACK_SCROLLING | FLAG_AUTO_REFRESH_SCROLLING;

    private int mFlags;

    private RecyclerView mTarget;
    private OnLoadListener mLoadListener;
    private SwipeRefreshLayout.OnRefreshListener mRefreshListener;
    private RefreshLoader mFooterProgress;
    private RefreshHeader mHeaderProgress;
    private NestedScrollingParentHelper mNestedScrollingParentHelper;
    private NestedScrollingChildHelper mNestedScrollingChildHelper;

    private OnChildScrollDownCallback mOnChildScrollDownCallback;
    private OnChildScrollUpCallback mOnChildScrollUpCallback;

    private OverScroller mScroller;
    private final int[] mScrollOffset = new int[2];
    private final int[] mScrollConsumed = new int[2];
    private int mSpringBackOffset;

    public MySwipeRefreshLayout(Context context) {
        this(context, null);
    }

    public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MySwipeRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public void setFinished(boolean finished) {
//        mFlags |= finished ? FLAG_FINISHED : 0;
//        setLoading(false);
        setStatus(FLAG_FREE | (finished ? FLAG_FINISHED : 0), false);
    }

    public boolean autoRefresh() {
        if (!mScroller.isFinished() || isRefreshing() || isLoading() || canChildScrollUp()) {
            return false;
        }

        startAutoRefreshScroll();
        return true;
    }

    public void autoPostRefresh() {
        post(new Runnable() {
            @Override
            public void run() {
                if (!mScroller.isFinished() || isRefreshing() || isLoading() || canChildScrollUp()) {
                    return;
                }
                startAutoRefreshScroll();

            }
        });
    }


    private void init() {
//        mFooterProgress = new ProgressBar(getContext());
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        mScroller = new OverScroller(getContext());
        mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);

        mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
        setNestedScrollingEnabled(true);
        createHeaderProgress();
        addView((View) mHeaderProgress);
        createFooterProgress();
        addView((View) mFooterProgress);

//        setOnChildScrollDownCallback(myOnChildScrollDownCallback);

    }

    public void setOnChildScrollUpCallback(@Nullable OnChildScrollUpCallback callback) {
//        super.setOnChildScrollUpCallback(callback);
        mOnChildScrollUpCallback = callback;
    }

    public void setOnChildScrollDownCallback(OnChildScrollDownCallback callback) {
        mOnChildScrollDownCallback = callback;
    }

    OnChildScrollUpCallback myOnChildScrollUpCallback = new OnChildScrollUpCallback() {
        @Override
        public boolean canChildScrollUp(@NonNull MySwipeRefreshLayout parent, @Nullable View child) {
            if (isLoading()) {
                return true;
            } else {
                return mOnChildScrollUpCallback != null && mOnChildScrollUpCallback.canChildScrollUp(parent, child);
            }
        }


    };

    OnChildScrollDownCallback myOnChildScrollDownCallback = new OnChildScrollDownCallback() {
        @Override
        public boolean canChildScrollDown(@NonNull MySwipeRefreshLayout parent, @Nullable View child) {
            if (isRefreshing() || isFinished()) {
                return true;
            } else {
                return mOnChildScrollDownCallback != null && mOnChildScrollDownCallback.canChildScrollDown(parent, child);
            }
        }
    };

    public boolean isRefreshing() {
        return (mFlags & FLAG_REFRESHING) != 0;
    }

    public boolean isLoading() {
        return (mFlags & FLAG_LOADINGING) != 0;
    }

    private void createFooterProgress() {
        if (mFooterProgress == null) {
            mFooterProgress = new RefreshLoaderView(getContext());
            ((View) mFooterProgress).setVisibility(View.VISIBLE);
//            addView(mFooterProgress);
        }
    }

    private void createHeaderProgress() {
        if (mHeaderProgress == null) {
            mHeaderProgress = new RefreshHeaderView(getContext());
            ((View) mHeaderProgress).setVisibility(View.VISIBLE);
//            addView(mFooterProgress);
        }
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        if (mHeaderProgress == null) {
//            createHeaderProgress();
//            final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
//            addViewInLayout(mHeaderProgress, getChildCount(), params, true);
//        }
        ((View) mHeaderProgress).measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.AT_MOST));
//        if (mFooterProgress == null) {
//            createFooterProgress();
//            final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
//            addViewInLayout(mFooterProgress, getChildCount(), params, true);
//        }
        ((View) mFooterProgress).measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.AT_MOST));

        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        mTarget.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));


    }


    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        Log.i("@@", "@@@:onLayout");
        final View headerView = (View) mHeaderProgress;
        final int headerLeft = getPaddingLeft();
        final int headerTop = getPaddingTop() - headerView.getMeasuredHeight();
        headerView.layout(headerLeft, headerTop, headerLeft + headerView.getMeasuredWidth(), headerTop + headerView.getMeasuredHeight());


        final View footerView = (View) mFooterProgress;
        final int footerLeft = getPaddingLeft();
        final int footerTop = getMeasuredHeight() - getPaddingBottom();
        footerView.layout(footerLeft, footerTop, footerLeft + footerView.getMeasuredWidth(), footerTop + footerView.getMeasuredHeight());


        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        final View child = mTarget;

        final int childLeft = getPaddingLeft();
        final int childTop = getPaddingTop();
        final int childWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
        final int childHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);

    }


    private void ensureTarget() {

        if (mTarget == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (child instanceof RecyclerView) {
                    mTarget = (RecyclerView) child;
//                    return;
                    break;
                }
            }
        }
    }


    public void setOnLoadListener(OnLoadListener listener) {
        mLoadListener = listener;
    }

    public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) {
        mRefreshListener = listener;
    }


    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return mNestedScrollingChildHelper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes, int type) {
        return mNestedScrollingChildHelper.startNestedScroll(axes, type);
    }

    @Override
    public void stopNestedScroll(int type) {
        mNestedScrollingChildHelper.stopNestedScroll(type);
    }

    @Override
    public boolean hasNestedScrollingParent(int type) {
        return mNestedScrollingChildHelper.hasNestedScrollingParent(type);
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type) {
        return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow, int type) {

        return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) {
        return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;


    }


    @Override
    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes, int type) {
//        onNestedScrollAccepted(child, target, axes);
        mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes, type);
        startNestedScroll(axes, type);
        mSpringBackOffset = 0;
    }

    @Override
    public void onStopNestedScroll(@NonNull View target, int type) {

        dispatchRefresh();
        stopNestedScroll(type);
        mNestedScrollingParentHelper.onStopNestedScroll(target, type);
    }


    private boolean canNotifyToUser(int top) {
        //如果越界，根据当前位置，计算是否可以通知用户刷新或加载
        if (top < 0) {
            return !canChildScrollUp() && !isLoading();
        } else if (top > 0) {
            return !isFinished() && !canChildScrollDown() && !isRefreshing();
        }
        return false;
    }

    private void moveChild(int top) {
        scrollTo(0, top);
    }


    private void showProgress(int flag) {
        final View headerView = (View) mHeaderProgress;
        final View footerView = (View) mFooterProgress;
        if (flag == FLAG_REFRESHING) {
            if (headerView.getVisibility() != VISIBLE) {
                headerView.setVisibility(VISIBLE);
            }
        } else if (flag == FLAG_LOADINGING) {
            if (footerView.getVisibility() != VISIBLE) {
                footerView.setVisibility(VISIBLE);
            }
        }
    }

    private void hideProgress(int flag) {
        final View headerView = (View) mHeaderProgress;
        final View footerView = (View) mFooterProgress;
        if (flag == FLAG_REFRESHING) {
            if (headerView.getVisibility() != GONE) {
                headerView.setVisibility(GONE);
            }
        } else if (flag == FLAG_LOADINGING) {
            if (footerView.getVisibility() != GONE) {
                footerView.setVisibility(GONE);
            }

        }
    }


    @Override
    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {


        mSpringBackOffset = 0;
        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, mScrollOffset, type);
        final int dy = dyUnconsumed + mScrollOffset[1];

        if (dy != 0) {
            boolean canScroll = mScroller.isFinished() && dy > 0 || type == ViewCompat.TYPE_TOUCH || isRefreshing();
            if (canScroll) {

                final int oldScrollY = getScrollY();
                scrollVerticalByTouch(oldScrollY, (int) (dy * SCROLL_CONSUMED_RATIO));
//                newTotalUnConsumed = Math.min(mHeaderProgress.getHeight(), Math.max(-mFooterProgress.getHeight(), newTotalUnConsumed));


            }
        }
    }


    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @Nullable int[] consumed, int type) {


        if (mScroller.isFinished()) {
            final int myDy = dy - mSpringBackOffset;
            final int oldScrollY = getScrollY();
            int newScrollY = prevScrollVerticalByTouch(oldScrollY, myDy);
            int consumedY = newScrollY - oldScrollY;
            consumed[1] = consumedY;
        }


        consumed[1] += mSpringBackOffset;

//        unconsumed += mMyOffsetScrollY;
        if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], mScrollConsumed, null, type)) {
            consumed[0] += mScrollConsumed[0];
            consumed[1] += mScrollConsumed[1];
        }


    }

    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        return dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        return dispatchNestedPreFling(velocityX, velocityY);
    }

    @Override
    public int getNestedScrollAxes() {
        return mNestedScrollingParentHelper.getNestedScrollAxes();
    }

    public interface OnLoadListener {
        void onLoading();
    }


    private boolean mIsBeginDragged = false;
    //    private float mInitialDownY;
//    private float mInitialMotionY;
    private int mLastMotionY;
    private int mTouchSlop;


    boolean overScroll(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeXLeft, int scrollRangeYTop, int scrollRangeXRight, int scrollRangeYBottom, int maxOverScrollX, int maxOverScrollY) {
        int newScrollX = scrollX + deltaX;
        int newScrollY = scrollY + deltaY;
        final int left = -scrollRangeXLeft - maxOverScrollX;
        final int right = scrollRangeXRight + maxOverScrollX;
        final int top = -scrollRangeYTop - maxOverScrollY;
        final int bottom = scrollRangeYBottom + maxOverScrollY;

        boolean clampedX = false;
        if (newScrollX > right) {
            newScrollX = right;
            clampedX = true;
        } else if (newScrollX < left) {
            newScrollX = left;
            clampedX = true;
        }
        boolean clampedY = false;
        if (newScrollY > bottom) {
            newScrollY = bottom;
            clampedY = true;
        } else if (newScrollY < top) {
            newScrollY = top;
            clampedY = true;
        }
        if (clampedX) {
            mScroller.springBack(newScrollX, newScrollY, 0, 0, -scrollRangeYTop, scrollRangeYBottom);
        }

        onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);

        return clampedX || clampedY;

    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
//        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
//        super.scrollTo(scrollX, scrollY);
        moveChild(scrollY);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        ensureTarget();

        /**
         *
         * 如果正在loading或者loading结束后正在scrolling,onStartNestedScroll会返回false,此时会得到触摸时间，所以要判断mLoading||!mScroller.isFinished()
         * */


        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                mIsBeginDragged = false;
                mLastMotionY = (int) ev.getY();
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                final float y = ev.getY();
                final float yDiff = Math.abs(y - mLastMotionY);
                if (yDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0) {
                    mLastMotionY = (int) y;
                    mIsBeginDragged = true;
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                }

                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsBeginDragged = false;
                stopNestedScroll(ViewCompat.TYPE_TOUCH);
                break;

        }


        return mIsBeginDragged;
    }

    //
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        /**
         *
         * 如果正在loading或者loading结束后正在scrolling,onStartNestedScroll会返回false,此时会得到触摸时间，所以要判断mLoading||!mScroller.isFinished()
         * */


        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mIsBeginDragged = false;
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
                break;
            case MotionEvent.ACTION_MOVE:
                final int y = (int) ev.getY();
                int deltaY = mLastMotionY - y;


                if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset,
                        ViewCompat.TYPE_TOUCH)) {
                    deltaY -= mScrollConsumed[1];

                }


                if (Math.abs(deltaY) > mTouchSlop && !mIsBeginDragged) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    mIsBeginDragged = true;
                    if (deltaY > 0) {
                        deltaY -= mTouchSlop;
                    } else {
                        deltaY += mTouchSlop;
                    }
                }

                if (mIsBeginDragged) {
                    mLastMotionY = y - mScrollOffset[1];
                    final int oldY = getScrollY();

                    if (mScroller.isFinished()) {
                        scrollVerticalByTouch(oldY, deltaY);
                    }
//                    Log.i("@@@@@", "@@@@@@@@:deltaY" + deltaY);


                    final int scrolledDeltaY = getScrollY() - oldY;
                    final int unconsumedY = deltaY - scrolledDeltaY;
                    if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset,
                            ViewCompat.TYPE_TOUCH)) {
                        mLastMotionY -= mScrollOffset[1];
                    }
                }


                break;
            case MotionEvent.ACTION_UP:
                if (mIsBeginDragged) {
                    dispatchRefresh();
                }
                mIsBeginDragged = false;
                stopNestedScroll(ViewCompat.TYPE_TOUCH);
                break;
            case MotionEvent.ACTION_CANCEL:
                mIsBeginDragged = false;
                stopNestedScroll(ViewCompat.TYPE_TOUCH);
                break;
        }

//        Log.i("@@@@@@", "@@@@@y:" + ev.getY() + ",last:" + mLastMotionY);

        return true;
    }


    private boolean dispatchRefresh() {
        int totalUnConsumed = getScrollY();
        final boolean canNotifyUserToRefresh = canNotifyToUser(totalUnConsumed);
        if (totalUnConsumed < 0 && canNotifyUserToRefresh) {
            if (!isRefreshing()) {
                if (mHeaderProgress.onStartRefreshing(totalUnConsumed)) {
                    mHeaderProgress.onRefreshingAccepted();
                    setStatus(FLAG_REFRESHING, true);
                } else {
//                    startSpringBackScroll();
                    reset(FLAG_FREE);
                }

            }

//            if (setStatus(FLAG_REFRESHING, true)) {
//                mHeaderProgress.onStartRefreshing(totalUnConsumed);
//            }
            return true;
        }
        return false;
    }

    private boolean isBusy() {
        return (mFlags & MASK_BUSY) != 0;
    }


    private int prevScrollVerticalByTouch(int oldScroll, int deltaY) {
        if (deltaY < 0 && oldScroll > 0) {
            int newScrollY = oldScroll + deltaY;
            if (newScrollY < 0) {
                newScrollY = 0;
            }
            moveChild(newScrollY);
            if (newScrollY == 0) {
                hideProgress(FLAG_LOADINGING);
            } else {
                showProgress(FLAG_LOADINGING);
            }
            mFooterProgress.onThroughFooter(newScrollY, isLoading(), false);
            return newScrollY;

        } else if (deltaY > 0 && oldScroll < 0) {
            int newScrollY = oldScroll + deltaY;
            if (newScrollY > 0) {
                newScrollY = 0;
            }
            moveChild(newScrollY);
            if (newScrollY == 0) {
                hideProgress(FLAG_REFRESHING);
            } else {
                showProgress(FLAG_REFRESHING);
            }
            mHeaderProgress.onThroughHeader(newScrollY, isRefreshing(), false);

            return newScrollY;
        }
        return oldScroll;
    }


    private int scrollVerticalByTouch(int oldScrollY, int deltaY) {
        return scrollVertical(oldScrollY, deltaY, true);

    }

    private int scrollVertical(int oldScrollY, int deltaY, boolean touch) {
        int newScrollY = oldScrollY + deltaY;
        final boolean canNotify = canNotifyToUser(newScrollY);
        final int range = getScrollRange(deltaY, canNotify);

        if (deltaY > 0) {
            if (newScrollY > range) {
                newScrollY = range;
            }
            moveChild(newScrollY);

            if (canNotify) {
                showProgress(FLAG_LOADINGING);

                if (!isLoading()) {
                    if (mFooterProgress.onStartLoading(newScrollY)) {
                        mFooterProgress.onLoadingingAccepted();
                        setStatus(FLAG_LOADINGING, true);
                    }
                    mFooterProgress.onThroughFooter(newScrollY, isLoading(), false);

                } else {
                    mFooterProgress.onThroughFooter(newScrollY, isLoading(), false);
                }


            } else {
                hideProgress(FLAG_LOADINGING);
            }
            return newScrollY;

        } else if (deltaY < 0) {
            if (newScrollY < range) {
                newScrollY = range;
            }
            moveChild(newScrollY);
            if (canNotify) {
                showProgress(FLAG_REFRESHING);
                if (!touch) {
                    if (!isRefreshing()) {
                        if (mHeaderProgress.onStartRefreshing(newScrollY)) {
                            mHeaderProgress.onRefreshingAccepted();
                            setStatus(FLAG_REFRESHING, true);
                        }
                        mHeaderProgress.onThroughHeader(newScrollY, isRefreshing(), false);
                    } else {
                        mHeaderProgress.onThroughHeader(newScrollY, isRefreshing(), false);
                    }
                } else {
                    mHeaderProgress.onThroughHeader(newScrollY, isRefreshing(), false);
                }


//                moveUpAndNotify(newScrollY);
            } else {
                hideProgress(FLAG_REFRESHING);
            }
            return newScrollY;
        }

        return oldScrollY;

    }


    int getScrollRange(int deltaY, boolean crossBroader) {
        int scrollRange = 0;
        if (deltaY > 0) {
            if (!crossBroader) {
                scrollRange = 0;
            } else {
                scrollRange = ((View) mFooterProgress).getMeasuredHeight();
            }

        } else if (deltaY < 0) {
            if (!crossBroader) {
                scrollRange = 0;
            } else {
                scrollRange = -((View) mHeaderProgress).getMeasuredHeight() - OVERSTEP_HEIGHT;
            }
        }


        return scrollRange;
    }

    public boolean isFinished() {
        return (mFlags & FLAG_FINISHED) != 0;
    }


    private void performeLoadingCallback() {
        if (mLoadListener != null) {
            mLoadListener.onLoading();
        }
    }

    private void performeRefreshingCallback() {
        if (mRefreshListener != null) {
            mRefreshListener.onRefresh();

        }
    }


    boolean setStatus(int flag, boolean notify) {
        int busyFlags = mFlags & MASK_BUSY;
        if (busyFlags != flag) {
            ensureTarget();
            switch (flag & MASK_BUSY) {
                case FLAG_REFRESHING:
                    if (busyFlags != FLAG_LOADINGING) {
                        mFlags |= FLAG_REFRESHING;
                        if (notify) {
                            performeRefreshingCallback();
                        }
                        return true;
                    }
                    return false;
                case FLAG_LOADINGING:
                    if (busyFlags != FLAG_REFRESHING && !isFinished()) {
                        mFlags |= FLAG_LOADINGING;
                        if (notify) {
                            performeLoadingCallback();
                        }
                        return true;
                    }

                    return false;
                case FLAG_FREE:
                    reset(busyFlags);
                    mFlags &= ~busyFlags;//busyFlags置空
                    mFlags &= ~FLAG_FINISHED;
                    mFlags |= flag & FLAG_FINISHED;//重新设置是否finished
                    return true;
            }
        }


        return false;
    }


    void reset(int status) {
        if (status == FLAG_REFRESHING) {
            mHeaderProgress.onFinishRefreshing();
        } else if (status == FLAG_LOADINGING) {
            mFooterProgress.onFinishLoading();
        }
        mTarget.stopScroll();
        int totalUnConsumed = -getScrollY();
        if (totalUnConsumed != 0) {
            mSpringBackOffset = getScrollY();
//            if (!refresh) {
//                mTarget.scrollBy(0, -mTotalUnconsumed);
//            }


//            if (!mBlockSpringBack) {
//                startSpringBackScroll();
//            } else if (refresh) {
//                hideProgress(true);
//            } else {
//                hideProgress(false);
//            }
            startSpringBackScroll();
//            moveChild(0, false);
        }
    }

    private void startAutoRefreshScroll() {
        if (mScroller.isFinished()) {
            scrollTo(0, 0);//先将位置回到0
            mFlags |= FLAG_AUTO_REFRESH_SCROLLING;
            final int headerTop = -((View) mHeaderProgress).getHeight();
            mScroller.startScroll(0, 0, 0, headerTop);
        }
    }

    private void startSpringBackScroll() {
        if (mScroller.isFinished() && getScrollY() != 0) {
            mFlags |= FLAG_BACK_SCROLLING;
//            Log.i("@@@@@@@", "@@@@@@:reset startscroll");
            mScroller.startScroll(0, getScrollY(), 0, -getScrollY());
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    private void springBackScroll(int top) {
        moveChild(top);
        if (top < 0) {
            mHeaderProgress.onThroughHeader(top, isRefreshing(), true);
        } else if (top > 0) {
            mFooterProgress.onThroughFooter(top, isLoading(), true);

        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            switch (mFlags & MASK_SCROLLING) {
                case FLAG_BACK_SCROLLING: {
                    springBackScroll(mScroller.getCurrY());
//                    moveChild(mScroller.getCurrY());
//                    final int oldScrollY = getScrollY();
//                    final int deltaY = mScroller.getCurrY() - oldScrollY;
//                    final View head = (View) mHeaderProgress;
//                    final View foot = (View) mFooterProgress;
//                    scrollVertical(oldScrollY, deltaY, false);


//                    overScroll(0, deltaY, 0, oldScrollY, 0, head.getMeasuredHeight(), 0, foot.getMeasuredHeight(), 0, 0);
                    ViewCompat.postInvalidateOnAnimation(this);

                }
                break;
                case FLAG_AUTO_REFRESH_SCROLLING:
                    final int oldScrollY = getScrollY();
                    final int deltaY = mScroller.getCurrY() - oldScrollY;
                    scrollVertical(oldScrollY, deltaY, false);
                    ViewCompat.postInvalidateOnAnimation(this);
//                    moveChild(mScroller.getCurrY());
                    break;
            }


        } else {
            mFlags &= ~MASK_SCROLLING;
        }

    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

    }

    public interface OnChildScrollUpCallback {
        boolean canChildScrollUp(@NonNull MySwipeRefreshLayout parent, @Nullable View child);
    }

    public boolean canChildScrollDown() {
        if (mOnChildScrollDownCallback != null) {
            return mOnChildScrollDownCallback.canChildScrollDown(this, mTarget);
        }
        return false;


//        return false;
    }

    public boolean canChildScrollUp() {
//        if (myOnChildScrollUpCallback != null) {
//            return myOnChildScrollUpCallback.canChildScrollUp(this, mTarget);
//        }
        if (mOnChildScrollUpCallback != null) {
            return mOnChildScrollUpCallback.canChildScrollUp(this, mTarget);
        }
        return false;
    }


//    public static class EarlyScrollListener extends RecyclerView.OnScrollListener {
//        /**
//         * RecyclerView滑动的时候，滑动到倒数几个的时候，进行预先loading
//         */
//        private int mEndNum;
//
//        public EarlyScrollListener(MySwipeRefreshLayout refreshLayout, int endNum) {
//            this.mRefreshLayout = refreshLayout;
//            this.mEndNum = endNum;
//        }
//
//        MySwipeRefreshLayout mRefreshLayout;
//        private int mState;
//        private boolean mLastVisible;
//
//        @Override
//        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
//            mState = newState;
//            doLoading();
//        }
//
//        @Override
//        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
//            final RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(recyclerView.getAdapter() == null ? -1 : recyclerView.getAdapter().getItemCount() - mEndNum);
//            mLastVisible = viewHolder != null;
//            doLoading();
//
//        }
//
//        private void doLoading() {
//            if (!mRefreshLayout.isRefreshing() && !mRefreshLayout.isLoading() && mLastVisible && mState != RecyclerView.SCROLL_STATE_IDLE && !mRefreshLayout.isFinished()) {
//                mRefreshLayout.setLoading(true);
//            }
//        }
//    }

    public interface OnChildScrollDownCallback {
        boolean canChildScrollDown(@NonNull MySwipeRefreshLayout parent, @Nullable View child);
    }

}
